/* =============================================================
 * date-utils.js v1.1.0
 * =============================================================
 * Original written by Ysy
 * =============================================================
 * Date 15/06/2021
 * ============================================================ */
import CommonUtils from "@/utils/common-utils";
import NumberUtils from "@/utils/number-utils";

export default class DateUtils {

  /**
   * @Description 获取当前日期时间戳
   * @returns {number}
   */
  static getNowDateTimestamp() {
    return Date.now();
  }

  /**
   * @Description 获取指定时间戳
   * @param dateStr
   * @returns {number}
   */
  static getDateTimestamp( dateStr ) {
    let date = new Date( dateStr );
    return date.getTime();
  }

  /**
   * @Description 日期格式转字符串格式
   * @param date  需要格式化的日期
   * @param fmt   格式化类型  yyyy-MM-dd hh:mm:ss.S
   * @returns {*|boolean|void|Promise<unknown>|Promise<any>|string}
   */
  static dateToString( date, fmt ) {
    let o = {
      "M+" : date.getMonth() + 1,                 // 月份
      "d+" : date.getDate(),                      // 日
      "h+" : date.getHours(),                     // 小时
      "m+" : date.getMinutes(),                   // 分
      "s+" : date.getSeconds(),                   // 秒
      // "q+": Math.floor((data.getMonth() + 3) / 3), // 季度
      "q+" : Math.floor( NumberUtils.division( NumberUtils.addition( date.getMonth(), 3 ), 3 ) ), // 季度
      "S" : date.getMilliseconds()                // 毫秒
    };
    if ( /(y+)/.test( fmt ) )
      fmt = fmt.replace( RegExp.$1, ( date.getFullYear() + "" ).substr( 4 - RegExp.$1.length ) );
    for ( let k in o )
      if ( new RegExp( "(" + k + ")" ).test( fmt ) )
        fmt = fmt.replace( RegExp.$1, ( Object.is( RegExp.$1.length, 1 ) ) ? ( o[ k ] ) : ( ( "00" + o[ k ] ).substr( ( "" + o[ k ] ).length ) ) );
    return fmt;
  }

  /**
   * @Description 获取当前日期
   * @Date 10:30 2021/6/15
   * @param fmt   格式化类型  yyyy-MM-dd hh:mm:ss.S
   * @returns {*|boolean|void|Promise<unknown>|Promise<any>|string}
   */
  static getNowDate( fmt ) {
    let date = new Date();
    return this.dateToString( date, fmt );
  }

  /**
   * @Description 获取距当前多少天数的日期
   * @param day
   * @returns {*|boolean|void|Promise<unknown>|Promise<*>|string}
   */
  static getDayDate( day ) {
    let today = new Date();

    let targetDaySeconds = today.getTime() + 1000 * 60 * 60 * 24 * day;
    today.setTime( targetDaySeconds );

    return this.dateToString( today, "yyyy-MM-dd HH:mm:ss" );
  }

  /**
   * @Description // 获取当前日期
   * @Date 10:30 2021/6/15
   **/
  static getNowWeek() {
    let days = new Date().getDay();

    switch ( days ) {
      case 1:
        days = "星期一";
        break;
      case 2:
        days = "星期二";
        break;
      case 3:
        days = "星期三";
        break;
      case 4:
        days = "星期四";
        break;
      case 5:
        days = "星期五";
        break;
      case 6:
        days = "星期六";
        break;
      case 0:
        days = "星期日";
        break;
    }

    return days;
  }

  /**
   * @Descripttion: 时间戳转日期
   * @Author: Ysy
   * @Date: 2021-07-07 15:06:04
   * @param timeStamp
   * @param {*} fmt
   * @return {*}
   */
  static timeStampToDate( timeStamp, fmt ) { // DateUtils.timeStampToDate(1622952000000,"yyyy-MM-dd hh:mm:ss");

    if ( CommonUtils.isString( timeStamp ) ) {
      timeStamp = new Date( parseInt( timeStamp ) );
    } else if ( CommonUtils.isNumber( timeStamp ) ) {
      timeStamp = new Date( timeStamp );
    }


    if ( /(y+)/.test( fmt ) ) {
      fmt = fmt.replace( RegExp.$1, ( timeStamp.getFullYear() + '' ).substr( 4 - RegExp.$1.length ) );
    }

    let o = {
      'M+' : timeStamp.getMonth() + 1,
      'd+' : timeStamp.getDate(),
      'h+' : timeStamp.getHours(),
      'm+' : timeStamp.getMinutes(),
      's+' : timeStamp.getSeconds()
    };

    let padLeftZero = ( str ) => {
      return ( '00' + str ).substr( str.length );
    }

    for ( let k in o ) {
      if ( new RegExp( `(${k})` ).test( fmt ) ) {
        let str = o[ k ] + '';
        fmt = fmt.replace( RegExp.$1, ( RegExp.$1.length === 1 ) ? str : padLeftZero( str ) );
      }
    }

    return fmt;
  }

  /**
   * @Author Ysy
   * @Description // 获取指定时区时间
   * @Param timezone
   * @Date 3:24 2022/7/20
   **/
  static getTimeZoneDate( timezone ) {
    let offset_GMT = new Date().getTimezoneOffset() // 本地时间和格林威治的时间差，单位为分钟
    let nowDate = new Date().getTime() // 本地时间距 1970 年 1 月 1 日午夜（GMT 时间）之间的毫秒数
    return new Date( nowDate + offset_GMT * 60 * 1000 + timezone * 60 * 60 * 1000 )
  }

  /**
   * @Author Ysy
   * @Description // 根据传入时间，转换差异时区时间
   * @Date 3:24 2022/7/20
   * @param date
   * @param timezone
   **/
  static getTimeZoneDateTransform( date, timezone ) {
    let nowDate = date.getTime() // 当前时间距 1970 年 1 月 1 日午夜（GMT 时间）之间的毫秒数
    return new Date( nowDate - timezone * 60 * 60 * 1000 )
  }

  /**
   * @Author Ysy
   * @Description // 获取当前时区
   * @Date 3:24 2022/7/20
   **/
  static getCurrentZone() {
    // 获取时区;  目标时区时间，东八区   东时区正数 西市区负数
    return new Date().getTimezoneOffset() / 60 * -1
  }

  /**
   * @Author Ysy
   * @Description // 获取当前时区名称
   * @Date 3:24 2022/7/20
   **/
  static getZoneName() {
    let tmSummer = new Date( Date.UTC( 2005, 6, 30, 0, 0, 0, 0 ) )
    let so = -1 * tmSummer.getTimezoneOffset()
    let tmWinter = new Date( Date.UTC( 2005, 12, 30, 0, 0, 0, 0 ) )
    let wo = -1 * tmWinter.getTimezoneOffset()
    if ( -660 === so && -660 === wo ) return 'Pacific/Midway'
    if ( -600 === so && -600 === wo ) return 'Pacific/Tahiti'
    if ( -570 === so && -570 === wo ) return 'Pacific/Marquesas'
    if ( -540 === so && -600 === wo ) return 'America/Adak'
    if ( -540 === so && -540 === wo ) return 'Pacific/Gambier'
    if ( -480 === so && -540 === wo ) return 'US/Alaska'
    if ( -480 === so && -480 === wo ) return 'Pacific/Pitcairn'
    if ( -420 === so && -480 === wo ) return 'US/Pacific'
    if ( -420 === so && -420 === wo ) return 'US/Arizona'
    if ( -360 === so && -420 === wo ) return 'US/Mountain'
    if ( -360 === so && -360 === wo ) return 'America/Guatemala'
    if ( -360 === so && -300 === wo ) return 'Pacific/Easter'
    if ( -300 === so && -360 === wo ) return 'US/Central'
    if ( -300 === so && -300 === wo ) return 'America/Bogota'
    if ( -240 === so && -300 === wo ) return 'US/Eastern'
    if ( -240 === so && -240 === wo ) return 'America/Caracas'
    if ( -240 === so && -180 === wo ) return 'America/Santiago'
    if ( -180 === so && -240 === wo ) return 'Canada/Atlantic'
    if ( -180 === so && -180 === wo ) return 'America/Montevideo'
    if ( -180 === so && -120 === wo ) return 'America/Sao_Paulo'
    if ( -150 === so && -210 === wo ) return 'America/St_Johns'
    if ( -120 === so && -180 === wo ) return 'America/Godthab'
    if ( -120 === so && -120 === wo ) return 'America/Noronha'
    if ( -60 === so && -60 === wo ) return 'Atlantic/Cape_Verde'
    if ( 0 === so && -60 === wo ) return 'Atlantic/Azores'
    if ( 0 === so && 0 === wo ) return 'Africa/Casablanca'
    if ( 60 === so && 0 === wo ) return 'Europe/London'
    if ( 60 === so && 60 === wo ) return 'Africa/Algiers'
    if ( 60 === so && 120 === wo ) return 'Africa/Windhoek'
    if ( 120 === so && 60 === wo ) return 'Europe/Amsterdam'
    if ( 120 === so && 120 === wo ) return 'Africa/Harare'
    if ( 180 === so && 120 === wo ) return 'Europe/Athens'
    if ( 180 === so && 180 === wo ) return 'Africa/Nairobi'
    if ( 240 === so && 180 === wo ) return 'Europe/Moscow'
    if ( 240 === so && 240 === wo ) return 'Asia/Dubai'
    if ( 270 === so && 210 === wo ) return 'Asia/Tehran'
    if ( 270 === so && 270 === wo ) return 'Asia/Kabul'
    if ( 300 === so && 240 === wo ) return 'Asia/Baku'
    if ( 300 === so && 300 === wo ) return 'Asia/Karachi'
    if ( 330 === so && 330 === wo ) return 'Asia/Calcutta'
    if ( 345 === so && 345 === wo ) return 'Asia/Katmandu'
    if ( 360 === so && 300 === wo ) return 'Asia/Yekaterinburg'
    if ( 360 === so && 360 === wo ) return 'Asia/Colombo'
    if ( 390 === so && 390 === wo ) return 'Asia/Rangoon'
    if ( 420 === so && 360 === wo ) return 'Asia/Almaty'
    if ( 420 === so && 420 === wo ) return 'Asia/Bangkok'
    if ( 480 === so && 420 === wo ) return 'Asia/Krasnoyarsk'
    if ( 480 === so && 480 === wo ) return 'Beijing'//return 'Australia/Perth';
    if ( 540 === so && 480 === wo ) return 'Asia/Irkutsk'
    if ( 540 === so && 540 === wo ) return 'Asia/Tokyo'
    if ( 570 === so && 570 === wo ) return 'Australia/Darwin'
    if ( 570 === so && 630 === wo ) return 'Australia/Adelaide'
    if ( 600 === so && 540 === wo ) return 'Asia/Yakutsk'
    if ( 600 === so && 600 === wo ) return 'Australia/Brisbane'
    if ( 600 === so && 660 === wo ) return 'Australia/Sydney'
    if ( 630 === so && 660 === wo ) return 'Australia/Lord_Howe'
    if ( 660 === so && 600 === wo ) return 'Asia/Vladivostok'
    if ( 660 === so && 660 === wo ) return 'Pacific/Guadalcanal'
    if ( 690 === so && 690 === wo ) return 'Pacific/Norfolk'
    if ( 720 === so && 660 === wo ) return 'Asia/Magadan'
    if ( 720 === so && 720 === wo ) return 'Pacific/Fiji'
    if ( 720 === so && 780 === wo ) return 'Pacific/Auckland'
    if ( 765 === so && 825 === wo ) return 'Pacific/Chatham'
    if ( 780 === so && 780 === wo ) return 'Pacific/Enderbury'
    if ( 840 === so && 840 === wo ) return 'Pacific/Kiritimati'
    return 'US/Pacific'
  }

  /**
   * @Author Ysy
   * @Description // 根据北京时间，转换成当前时区时间
   * @Param bjTime
   * @Date 3:25 2022/7/20
   **/
  static calcBeiJingCurrentZoneTime( bjTime ) {
    bjTime = new Date( bjTime )
    let bjZone = 8//中国时区
    let timezone = this.getCurrentZone()// 当前时区 ,美国 -4，中国 8
    let dt = this.getTimeZoneDateTransform( bjTime, bjZone - timezone )
    return this.dateToString( dt, `yyyy-MM-dd hh:mm:ss` );
  }

  /**
   * @Author Ysy
   * @Description // 判断 time 是否在 2022-07-20 12:00:00 ~ 2022-07-20 18:00:00 时间段内
   * @Date 3:25 2022/7/20
   * @param time
   * @param beginTime
   * @param endTime
   **/
  static isTimeBetweenStartAndEnd( time, beginTime, endTime ) {
    let nowDate = time ? new Date( time ) : new Date()
    let beginDate = new Date( beginTime );
    let endDate = new Date( endTime );

    return nowDate.getTime() - beginDate.getTime() >= 0 && nowDate.getTime() <= endDate.getTime();
  }

  /**
   * @Author Ysy
   * @Description // 根据时间 yyyy-MM-dd hh:mm:ss 获取日期 yyyy-MM-dd
   * @Param time
   * @Date 15:59 2022/7/21
   **/
  static getDateByTime( time ) {
    if ( !time ) return ``

    time = new Date( time )
    let date = time.getDate();


    return this.dateToString( date, `yyyy-MM-dd` )
  }

  /**
   * @Author Ysy
   * @Description // 根据时间 yyyy-MM-dd hh:mm:ss 获取时间 hh:mm:ss
   * @Param time
   * @Date 15:59 2022/7/21
   **/
  static getTimeByTime( time ) {
    if ( !time ) return ``

    time = new Date( time )
    let date = time.getDate();

    return this.dateToString( date, `hh:mm:ss` )
  }

  /**
   * @Author Ysy
   * @Description // 日期格式化   dateFormat('2022-10-20', 'cn', '{y}-{m}-{d} {h}:{i}:{s}')
   * @Date 16:24 2022/10/20
   * @param time
   * @param language
   * @param pattern
   **/
  static dateFormat( time, language, pattern ) {
    if ( arguments.length === 0 || !time ) return null

    pattern = pattern ?? `{y}-{m}-{d} {h}:{i}:{s}`
    let date
    if ( CommonUtils.isObject( time ) ) {
      date = time
    } else {
      if ( CommonUtils.isString( time ) && /^[0-9]+$/.test( time ) ) {
        time = Number.parseInt( time )
      } else if ( CommonUtils.isString( time ) ) {
        time = time.replace( new RegExp( /-/gm ), '/' )
          .replace( 'T', ' ' ).replace( new RegExp( /\.[\d]{3}/gm ), '' )
      }
      if ( CommonUtils.isNumber( time ) && time.toString().length === 10 ) {
        time = time * 1000
      }
      date = new Date( time )
    }

    const formatObj = {
      y : date.getFullYear(),
      m : date.getMonth() + 1,
      d : date.getDate(),
      h : date.getHours(),
      i : date.getMinutes(),
      s : date.getSeconds(),
      a : date.getDay(),
    }

    const formatObjEn = {
      d : date.getDate(),
      m : date.getMonth(),
      y : date.getFullYear(),
    }

    const monthList = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec' ]
    const weekList = [ '日', '一', '二', '三', '四', '五', '六' ]

    const lang = language ?? 'cn'

    if ( lang !== 'cn' ) {
      return pattern.replace( /{([dmy])+}/g, ( result, key ) => {
        let value = formatObjEn[ key ]
        // Note: getDay() returns 0 on Sunday
        if ( key === 'm' ) {
          return monthList[ value ]
        }
        if ( result.length > 0 && value < 10 ) {
          value = '0' + value
        }
        return value || 0
      } )
    }

    return pattern.replace( /{([ymdhisa])+}/g, ( result, key ) => {
      let value = formatObj[ key ]
      // Note: getDay() returns 0 on Sunday
      if ( key === 'a' ) {
        return weekList[ value ]
      }
      if ( result.length > 0 && value < 10 ) {
        value = '0' + value
      }
      return value || 0
    } )
  }

};

